"""
交易信号生成器
基于技术分析生成买卖信号
"""
import logging
from typing import List, Dict, Optional
from datetime import datetime
from .technical_analyzer import TechnicalAnalyzer

logger = logging.getLogger(__name__)

class SignalGenerator:
    """交易信号生成器"""
    
    def __init__(self):
        self.analyzer = TechnicalAnalyzer()
    
    def generate_signal(self, symbol: str, price_data: List[Dict]) -> Optional[Dict]:
        """
        生成交易信号
        """
        if not price_data or len(price_data) < 30:
            return None
        
        # 获取技术指标
        indicators = self.analyzer.analyze_stock(price_data)
        current_price = price_data[-1]['close']
        
        # 分析信号
        signal_type, strength, reason = self._analyze_signals(indicators, current_price)
        
        # 计算目标价和止损价
        target_price, stop_loss = self._calculate_price_targets(
            current_price, signal_type, indicators
        )
        
        # 构建信号数据
        signal = {
            "symbol": symbol,
            "signal_type": signal_type,
            "strength": strength,
            "price": current_price,
            "action_price": current_price,  # 建议买入/卖出价格（买入信号的价格）
            "target_price": target_price,
            "stop_loss": stop_loss,
            "reason": reason,
            "indicators": self._format_indicators(indicators),
            "action_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
        
        return signal
    
    def _analyze_signals(self, indicators: Dict, current_price: float) -> tuple:
        """
        分析技术指标，生成信号
        返回: (signal_type, strength, reason)
        """
        buy_signals = []
        sell_signals = []
        reasons = []
        
        # MA 均线分析
        if indicators.get('ma5') and indicators.get('ma10'):
            if indicators['ma5'] > indicators['ma10']:
                buy_signals.append(20)
                reasons.append("MA5上穿MA10(金叉)")
            else:
                sell_signals.append(20)
                reasons.append("MA5下穿MA10(死叉)")
        
        # MACD 分析
        macd = indicators.get('macd')
        signal = indicators.get('signal')
        histogram = indicators.get('histogram')
        
        if macd and signal and histogram:
            if macd > signal and histogram > 0:
                buy_signals.append(25)
                reasons.append("MACD金叉")
            elif macd < signal and histogram < 0:
                sell_signals.append(25)
                reasons.append("MACD死叉")
        
        # RSI 分析
        rsi = indicators.get('rsi')
        if rsi:
            if rsi < 30:
                buy_signals.append(30)
                reasons.append(f"RSI超卖({rsi:.1f})")
            elif rsi > 70:
                sell_signals.append(30)
                reasons.append(f"RSI超买({rsi:.1f})")
            elif rsi < 50:
                buy_signals.append(10)
            else:
                sell_signals.append(10)
        
        # KDJ 分析
        k = indicators.get('k')
        d = indicators.get('d')
        j = indicators.get('j')
        
        if k and d and j:
            if k < 20 and d < 20:
                buy_signals.append(25)
                reasons.append(f"KDJ超卖(K:{k:.1f})")
            elif k > 80 and d > 80:
                sell_signals.append(25)
                reasons.append(f"KDJ超买(K:{k:.1f})")
        
        # 布林带分析
        boll_upper = indicators.get('upper')
        boll_lower = indicators.get('lower')
        
        if boll_upper and boll_lower:
            if current_price <= boll_lower:
                buy_signals.append(20)
                reasons.append("价格触及布林下轨")
            elif current_price >= boll_upper:
                sell_signals.append(20)
                reasons.append("价格触及布林上轨")
        
        # 综合判断
        buy_strength = sum(buy_signals)
        sell_strength = sum(sell_signals)
        
        if buy_strength > sell_strength:
            if buy_strength >= 70:
                return "STRONG_BUY", min(buy_strength, 100), "; ".join(reasons[:3])
            else:
                return "BUY", min(buy_strength, 100), "; ".join(reasons[:3])
        elif sell_strength > buy_strength:
            if sell_strength >= 70:
                return "STRONG_SELL", min(sell_strength, 100), "; ".join(reasons[:3])
            else:
                return "SELL", min(sell_strength, 100), "; ".join(reasons[:3])
        else:
            return "HOLD", 50, "多空均衡，建议持有观望"
    
    def _calculate_price_targets(self, current_price: float, signal_type: str, 
                                 indicators: Dict) -> tuple:
        """
        计算目标价和止损价
        """
        target_price = None
        stop_loss = None
        
        if signal_type in ["STRONG_BUY", "BUY"]:
            # 买入目标：基于技术分析计算合理目标价
            target_price = current_price
            
            # 1. 基于布林带的目标价
            if indicators.get('upper') and indicators.get('middle'):
                boll_target = indicators['upper'] * 0.95  # 布林上轨的95%
                target_price = max(target_price, boll_target)
            
            # 2. 基于MA均线的目标价
            if indicators.get('ma20'):
                ma_target = indicators['ma20'] * 1.05  # MA20的105%
                target_price = max(target_price, ma_target)
            
            # 3. 基于RSI的调整
            rsi = indicators.get('rsi')
            if rsi and rsi < 50:  # RSI较低时，目标价可以更高
                target_price = target_price * 1.08
            elif rsi and rsi > 60:  # RSI较高时，目标价保守一些
                target_price = target_price * 1.03
            
            # 4. 确保目标价至少比当前价高3%
            target_price = max(target_price, current_price * 1.03)
            
            # 5. 限制目标价不超过当前价的15%（避免过于乐观）
            target_price = min(target_price, current_price * 1.15)
            
            # 止损：布林下轨或下跌3-5%
            if indicators.get('lower'):
                stop_loss = min(indicators['lower'], current_price * 0.95)
            else:
                stop_loss = current_price * 0.95
                
        elif signal_type in ["STRONG_SELL", "SELL"]:
            # 卖出后的观察价位
            target_price = current_price * 0.92
            stop_loss = current_price * 1.03
        
        return (round(target_price, 2) if target_price else None, 
                round(stop_loss, 2) if stop_loss else None)
    
    def _format_indicators(self, indicators: Dict) -> Dict:
        """格式化技术指标为字典"""
        # 过滤 None 值并格式化
        formatted = {k: round(v, 2) if v is not None else None 
                    for k, v in indicators.items() if v is not None}
        return formatted
    
    def identify_trading_points(self, price_data: List[Dict]) -> List[Dict]:
        """
        识别历史买卖点 - 配对交易模式
        确保每个买入都有对应的卖出，一一对应
        """
        if len(price_data) < 30:
            return []
        
        trading_points = []
        
        # 交易状态
        has_position = False      # 是否持仓
        buy_price = 0.0          # 买入价格
        buy_index = 0            # 买入索引
        max_profit_rate = 0.0    # 最高盈利率
        
        # 止盈止损参数
        TARGET_PROFIT = 0.05     # 目标止盈 5%
        PULLBACK_STOP = 0.03     # 回撤止盈 3%
        STOP_LOSS = -0.05        # 止损 -5%
        MIN_PROFIT_FOR_TECH_SELL = 0.03  # 技术卖出最小盈利 3%
        
        # 滑动窗口分析
        for i in range(20, len(price_data)):
            window_data = price_data[max(0, i-20):i+1]
            indicators = self.analyzer.analyze_stock(window_data)
            
            current = price_data[i]
            current_price = current['close']
            signal_type, strength, reason = self._analyze_signals(
                indicators, current_price
            )
            
            # === 没有持仓，寻找买入机会 ===
            if not has_position:
                buy_signal = False
                buy_reason = ""
                
                # 强烈买入信号
                if signal_type == "STRONG_BUY" and strength >= 60:
                    buy_signal = True
                    buy_reason = reason
                
                # 局部低点买入
                elif signal_type == "BUY" and strength >= 50:
                    # 检查是否是局部低点
                    is_local_low = False
                    if i > 25 and i < len(price_data) - 5:
                        prev_prices = [price_data[j]['close'] for j in range(i-5, i)]
                        next_prices = [price_data[j]['close'] for j in range(i+1, min(i+6, len(price_data)))]
                        if current_price <= min(prev_prices + next_prices):
                            is_local_low = True
                    
                    if is_local_low:
                        buy_signal = True
                        buy_reason = reason + " (局部低点)"
                
                # 生成买入信号
                if buy_signal:
                    trading_points.append({
                        "timestamp": current['timestamp'],
                        "price": current_price,
                        "type": "BUY",
                        "reason": buy_reason,
                        "strength": strength
                    })
                    
                    # 更新持仓状态
                    has_position = True
                    buy_price = current_price
                    buy_index = i
                    max_profit_rate = 0.0
                    logger.info(f"买入信号: 价格={current_price:.2f}, 原因={buy_reason}")
            
            # === 持仓中，寻找卖出机会 ===
            else:
                # 计算当前盈利率
                profit_rate = (current_price - buy_price) / buy_price
                
                # 更新最高盈利率
                if profit_rate > max_profit_rate:
                    max_profit_rate = profit_rate
                
                sell_signal = False
                sell_reason = ""
                
                # 1. 目标止盈（优先级最高）
                if profit_rate >= TARGET_PROFIT:
                    sell_signal = True
                    sell_reason = f"达到止盈目标{TARGET_PROFIT*100:.0f}% (盈利{profit_rate*100:.1f}%)"
                
                # 2. 回撤止盈
                elif max_profit_rate - profit_rate >= PULLBACK_STOP:
                    sell_signal = True
                    sell_reason = f"从最高点{max_profit_rate*100:.1f}%回撤{PULLBACK_STOP*100:.0f}% (当前{profit_rate*100:.1f}%)"
                
                # 3. 止损
                elif profit_rate <= STOP_LOSS:
                    sell_signal = True
                    sell_reason = f"触及止损线 (亏损{abs(profit_rate)*100:.1f}%)"
                
                # 4. 技术卖出（盈利>3%时）
                elif profit_rate > MIN_PROFIT_FOR_TECH_SELL:
                    tech_sell_signals = 0
                    
                    # RSI超买
                    rsi = indicators.get('rsi')
                    if rsi and rsi > 70:
                        tech_sell_signals += 1
                    
                    # MACD死叉
                    macd = indicators.get('macd')
                    signal_line = indicators.get('signal')
                    histogram = indicators.get('histogram')
                    if macd and signal_line and histogram and histogram < 0:
                        tech_sell_signals += 1
                    
                    # MA死叉
                    if signal_type in ["STRONG_SELL", "SELL"]:
                        tech_sell_signals += 1
                    
                    # 满足2个以上技术卖出条件
                    if tech_sell_signals >= 2:
                        sell_signal = True
                        sell_reason = f"技术信号恶化 (盈利{profit_rate*100:.1f}%，提前止盈)"
                
                # 5. 强烈卖出信号（局部高点）
                elif signal_type == "STRONG_SELL" and strength >= 60:
                    # 检查是否是局部高点
                    is_local_high = False
                    if i > buy_index + 5 and i < len(price_data) - 5:
                        prev_prices = [price_data[j]['close'] for j in range(i-5, i)]
                        next_prices = [price_data[j]['close'] for j in range(i+1, min(i+6, len(price_data)))]
                        if current_price >= max(prev_prices + next_prices):
                            is_local_high = True
                    
                    if is_local_high and profit_rate > 0:  # 只在盈利时考虑技术卖出
                        sell_signal = True
                        sell_reason = f"局部高点 (盈利{profit_rate*100:.1f}%)"
                
                # 生成卖出信号
                if sell_signal:
                    trading_points.append({
                        "timestamp": current['timestamp'],
                        "price": current_price,
                        "type": "SELL",
                        "reason": sell_reason,
                        "strength": int((1 + profit_rate) * 100)  # 强度反映盈利情况
                    })
                    
                    # 重置持仓状态
                    has_position = False
                    logger.info(f"卖出信号: 价格={current_price:.2f}, 买入价={buy_price:.2f}, 盈利={profit_rate*100:.1f}%, 原因={sell_reason}")
        
        return trading_points

